#ifndef TEXTURE_H
#define TEXTURE_H

#include "perlin.h"
#include "rtw_stb_image.h"
#include "Vec3.h"

class Texture {
public:
    virtual ~Texture() = default;

    virtual Color value(double u, double v, const Point3& p) const = 0;
};

class SolidColor : public Texture {
public:
    SolidColor(const Color& albedo) : albedo(albedo) {}

    SolidColor(double red, double green, double blue);

    Color value(double u, double v, const Point3& p) const override {
        return albedo;
    }

private:
    Color albedo;
};

class CheckerTexture : public Texture {
public:
    CheckerTexture(double scale, std::shared_ptr<Texture> even, std::shared_ptr<Texture> odd)
        : inv_scale(1.0 / scale), even(even), odd(odd) {}

    CheckerTexture(double scale, const Color& c1, const Color& c2)
        : inv_scale(1.0 / scale),
        even(std::make_shared<SolidColor>(c1)),
        odd(std::make_shared<SolidColor>(c2))
    {}

    Color value(double u, double v, const Point3& p) const override {
        auto xInteger = int(std::floor(inv_scale * p.x()));
        auto yInteger = int(std::floor(inv_scale * p.y()));
        auto zInteger = int(std::floor(inv_scale * p.z()));

        bool isEven = (xInteger + yInteger + zInteger) % 2 == 0;

        return isEven ? even->value(u, v, p) : odd->value(u, v, p);
    }

private:
    double inv_scale;
    std::shared_ptr<Texture> even;
    std::shared_ptr<Texture> odd;
};


class ImageTexture : public Texture {
public:
    ImageTexture(const char* filename);

    Color value(double u, double v, const Point3& p) const override;

private:
    RTWImage image;
};

class NoiseTexture : public Texture {
public:
    NoiseTexture() = default;

    NoiseTexture(double scale);

    Color value(double u, double v, const Point3& p) const override;

private:
    Perlin noise;
    double scale;
};
#endif